

#include <acpi.h>
#include <string.h>
#include <debug.h>

int init_acpi(void)
{
	int ret = 0;
	
	acpi_rsdp_descriptor_t *rsdp;
	
	rsdp = find_rsdp((void*)RSDP_START, (void*)RSDP_END);
	if (rsdp == NULL)  // not found
	{
		// check EBDA area
		word *ebda = (word*)0x40e;
		void *start = (void*)(*ebda << 4);
		void *end = start + 0x400;
		
		rsdp = find_rsdp(start, end);
	}
		
	if (rsdp == NULL)
	{
		debugf("[ACPI] RSDP Not Found!\n");
		ret = ERR_ACPI_NOTFOUND;
	}
	else
	{
		debugf("[ACPI] RSDP v%d (%c%c%c%c%c%c) @ 0x%08x\n", rsdp->revision,
		 rsdp->oem_id[0], rsdp->oem_id[1], rsdp->oem_id[2], rsdp->oem_id[3], rsdp->oem_id[4],
		 rsdp->oem_id[5], rsdp);
		 
		// find other tables
		ret = acpi_parse_rsdp(rsdp);		 
	}
	
	return ret;
}

int acpi_parse_rsdp(acpi_rsdp_descriptor_t *rsdp)
{
	int ret = 0;
	
	acpi_rsdt_descriptor_t *rsdt;
	rsdt = (acpi_rsdt_descriptor_t*)rsdp->rsdt_addr;
	if (strncmp(rsdt->header.signature, "RSDT", 4) == 0)
	{
		int i;
		unsigned char checksum = 0;
		
		for (i = 0; i < rsdt->header.length; i++) {
			checksum += *(((unsigned char*)rsdt) + i);
		}
		
		if (checksum == 0)
		{
			int entries;
			acpi_system_descriptor_t *table;
			
			entries = (rsdt->header.length - sizeof(acpi_system_descriptor_t)) / sizeof(dword);
			debugf("[ACPI] RSDT v%d Found @ 0x%08x\n", rsdt->header.revision, rsdt);
			debugf("[ACPI] %d RSDT Entries\n", entries);
			
			for (i = 0; i < entries; i++)
			{
				table = rsdt->descriptor_ptrs[i];
				debugf("[ACPI] %c%c%c%c @ 0x%08x\n", table->signature[0],
				table->signature[1],table->signature[2],table->signature[3], table);
			}
		}
	}
	else
	{
		debugf("[ACPI] RSDT Not Found!\n");
		ret = ERR_ACPI_RSDT_NOTFOUND;
	}
	
	return ret;
}

acpi_rsdp_descriptor_t * find_rsdp(void *start, void *end)
{
	void * addr;
	acpi_rsdp_descriptor_t *rsdp = NULL;
	unsigned char checksum, i;
	unsigned char *ptr;
	
	for (addr = start; addr <= end; addr+=4)
	{		
		rsdp = (acpi_rsdp_descriptor_t*)addr;
		
		if (strncmp(rsdp->signature, RSDP_SIGNATURE, 8) == 0)
		{
			// found the descriptor
			// check which version & return that
			
			ptr = (unsigned char*)addr;
			checksum = 0;
			for (i = 0; i < sizeof(acpi_rsdp_descriptor_t); i++) 
				checksum += *(ptr++);
			
			if (checksum == 0)
				return addr;
		}
	}
	
	return NULL;
}
